#include <crt_path.h>
#include <crt_tstring.h>

#if (TARGET_OS == OS_WINDOWS)
    #define CTL_PluginExtName _T(".dll")
#elif (TARGET_OS == OS_POSIX)
    #define CTL_PluginExtName _T(".so")
#elif (TARGET_OS == OS_DARWIN)

    #ifdef __APPLE__
        #if _MACOSX_XCODE_
            #if (TARGET_OS_IOS == 1) && (TARGET_OS_IPHONE == 1)
                #define CTL_PluginExtName _T(".framework")
            #elif (TARGET_OS_MAC == 1)
                #define CTL_PluginExtName _T(".framework")
            #endif
        #else
            #define CTL_PluginExtName _T(".dylib")
        #endif
    #else

    #endif

#endif




int FileIsExist(const basic_tchar* lpFile)
{
	if (NULL == lpFile || 0x00 == (*lpFile))
		return S_ERROR;

#if (TARGET_OS == OS_WINDOWS)
	DWORD dwAttributes = GetFileAttributes(lpFile);
	if (0xFFFFFFFF == dwAttributes || dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
		return S_ERROR;
#elif (TARGET_OS == OS_POSIX)
	int fd = access(lpFile, F_OK);
	if (fd < 0)
		return S_ERROR;
#elif (TARGET_OS == OS_DARWIN)
    int fd = access(lpFile, F_OK);
    if (fd < 0)
        return S_ERROR;
#endif
	return S_SUCCESS;
}

int GetDynamicPath(void* szName, basic_tchar* szPath, ULONG ulen)
{
#if (TARGET_OS == OS_WINDOWS)
	GetModuleFileNameW(GetModuleHandle((basic_tchar*)szName), szPath, ulen);
#elif (TARGET_OS == OS_POSIX)
	Dl_info info = { 0x00 };
	int rc = 0;
	rc = dladdr((void*)szName, &info);
	string_strcpy(szPath, ulen, info.dli_fname);
	return rc == 0 ? S_SUCCESS : S_ERROR;
#elif (TARGET_OS == OS_DARWIN)
    Dl_info info = { 0x00 };
    int rc = 0;
    rc = dladdr((void*)szName, &info);
    string_strcpy(szPath, ulen, info.dli_fname);
    return rc == 0 ? S_SUCCESS : S_ERROR;
#endif
	return S_SUCCESS;
}

int GetExecutePath(_pinstance hInstance, basic_tchar* szPath, ULONG ulen)
{
	basic_tchar szBuf[MAX_PATH + 1] = {0x00 };

#if (TARGET_OS == OS_WINDOWS)
	GetModuleFileNameW(hInstance, szBuf, MAX_PATH);
	PathRemoveFileSpecW(szBuf);
	s_wstrcpy(szPath, ulen, szBuf);
	return   S_SUCCESS;
#elif (TARGET_OS == OS_POSIX)

	char* path_end = NULL;
	pid_t cur_pid = getpid();

	char cur_exe_link[MAX_PATH] = { 0 };
	sprintf(cur_exe_link, "/proc/%u/exe", cur_pid);
	int nCount = readlink(cur_exe_link, szBuf, MAX_PATH + 1);

	if (nCount < 0 || nCount >= MAX_PATH)
	{
		return FALSE;
	}

	int iloop;
	szBuf[nCount] = '\0';
	for (iloop = nCount; iloop >= 0; iloop--)
	{
		if (szBuf[iloop] == '/')
		{
			szBuf[iloop + 1] = '\0';
			break;
		}
	}

	s_strcpy(szPath, ulen, szBuf);
	return S_SUCCESS;
#elif (TARGET_OS == OS_DARWIN)
    int len = 0;
    char* p = NULL;
    uint32_t size = MAX_PATH;
    len = _NSGetExecutablePath(szBuf, &size);

    p = s_strrchr(szBuf, '/');
    if(p != NULL) {
        *p = 0;
    }
    s_strcpy(szPath, ulen, szBuf);
    return S_SUCCESS;
#endif
	return S_SUCCESS;
}

int GetDynamicName(const basic_tchar* pName, basic_tchar* pPluginName, ULONG ulen)
{

#if (TARGET_OS == OS_WINDOWS)
	s_wstrcat(pPluginName, ulen, pName);
#elif (TARGET_OS == OS_POSIX)
	s_strcat(pPluginName, ulen, _T("lib"));
	s_strcat(pPluginName, ulen, pName);
#elif (TARGET_OS == OS_DARWIN)
        
    #ifdef __APPLE__
        #if _MACOSX_XCODE_
            #if (TARGET_OS_IOS == 1) && (TARGET_OS_IPHONE == 1)
                s_strcat(pPluginName, ulen, pName);
                s_strcat(pPluginName, ulen, CTL_PluginExtName);
                s_strcat(pPluginName, ulen, "/");
                s_strcat(pPluginName, ulen, pName);
                return S_SUCCESS;
            #elif (TARGET_OS_MAC == 1)
                s_strcat(pPluginName, ulen, pName);
                s_strcat(pPluginName, ulen, CTL_PluginExtName);
                s_strcat(pPluginName, ulen, "/");
                s_strcat(pPluginName, ulen, pName);
                return S_SUCCESS;
            #endif
        #else
            s_strcat(pPluginName, ulen, _T("lib"));
            s_strcat(pPluginName, ulen, pName);
        #endif
    #else
    
    #endif
    
#endif
	tstring_strcat(pPluginName, ulen, CTL_PluginExtName);

	return S_SUCCESS;
}

#if (TARGET_OS == OS_WINDOWS)

int get_file_info(basic_tchar *cFilePath, get_file_cb entry, void* ctx)
{
	WIN32_FIND_DATA data;
	s_memset(&data, 0, sizeof(WIN32_FIND_DATA));

	HANDLE hFind = INVALID_HANDLE_VALUE;
	WCHAR cFullPath[MAX_PATH + 1] = { 0x00 };
	WCHAR cNewPath[MAX_PATH + 1] = { 0x00 };

	swprintf_s(cFullPath, MAX_PATH, L"%s\\*.*", cFilePath);
	hFind = FindFirstFile(cFullPath, &data);
	do
	{
		if ((!wcsicmp(L".", data.cFileName)) || (!wcsicmp(L"..", data.cFileName)))
		{
			continue;
		}
		if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			swprintf_s(cNewPath, MAX_PATH, L"%s\\%s", cFilePath, data.cFileName);
			get_file_info(cNewPath, entry, ctx);
		}
		else {

			if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {

			} 
			else if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {

			}
			else {
				swprintf_s(cFullPath, MAX_PATH, L"%s\\%s", cFilePath, data.cFileName);
				entry(cFullPath, ctx);
			}

		}

	} while (FindNextFile(hFind, &data));

	if (hFind != INVALID_HANDLE_VALUE)
	{
		FindClose(hFind);
		hFind = NULL;
	}

	return S_SUCCESS;
}

#elif (TARGET_OS == OS_POSIX)

#include <dirent.h>
#include <sys/stat.h>

#define FILE_MAX_PATH 512 

void dirwalk(basic_tchar *dir, int(*func)(basic_tchar *name, get_file_cb entry, void* ctx),
	get_file_cb entry,
	void* ctx)
{
	char name[FILE_MAX_PATH] = { 0x00 };
	struct dirent *dp = NULL;
	DIR *dfd = NULL;

	if ((dfd = opendir(dir)) == NULL) {
		fprintf(stderr, "dirwalk: can't open %s\n", dir);
		return;
	}

	while ((dp = readdir(dfd)) != NULL) {
		if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
			continue;
		}

		if (strlen(dir) + strlen(dp->d_name) + 2 > sizeof(name)) {
			fprintf(stderr, "dirwalk : name %s %s too long\n", dir, dp->d_name);
		}
		else {
			sprintf(name, "%s/%s", dir, dp->d_name);
			(*func)(name, entry, ctx);
		}
	}
	closedir(dfd);
}

int get_file_info(basic_tchar *name, get_file_cb entry, void* ctx)
{
	struct stat stbuf;

	if (stat(name, &stbuf) == -1) {
		fprintf(stderr, "file size: open %s failed\n", name);
		return S_ERROR;
	}

	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
		dirwalk(name, get_file_info, entry, ctx);
	}
	else {
		//printf("%8ld %s\n", stbuf.st_size, name);
		entry(name, ctx);
	}
	return S_SUCCESS;
}
#elif (TARGET_OS == OS_DARWIN)

#include <dirent.h>
#include <sys/stat.h>

#define FILE_MAX_PATH 512

void dirwalk(basic_tchar *dir, int(*func)(basic_tchar *name, get_file_cb entry, void* ctx),
    get_file_cb entry,
    void* ctx)
{
    char name[FILE_MAX_PATH] = { 0x00 };
    struct dirent *dp = NULL;
    DIR *dfd = NULL;

    if ((dfd = opendir(dir)) == NULL) {
        fprintf(stderr, "dirwalk: can't open %s\n", dir);
        return;
    }

    while ((dp = readdir(dfd)) != NULL) {
        if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
            continue;
        }

        if (strlen(dir) + strlen(dp->d_name) + 2 > sizeof(name)) {
            fprintf(stderr, "dirwalk : name %s %s too long\n", dir, dp->d_name);
        }
        else {
            sprintf(name, "%s/%s", dir, dp->d_name);
            (*func)(name, entry, ctx);
        }
    }
    closedir(dfd);
}

int get_file_info(basic_tchar *name, get_file_cb entry, void* ctx)
{
    struct stat stbuf;

    if (stat(name, &stbuf) == -1) {
        fprintf(stderr, "file size: open %s failed\n", name);
        return S_ERROR;
    }

    if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
        dirwalk(name, get_file_info, entry, ctx);
    }
    else {
        //printf("%8ld %s\n", stbuf.st_size, name);
        entry(name, ctx);
    }
    return S_SUCCESS;
}

#endif


int GetFiles(basic_tchar* szPath, get_file_cb entry, void* ctx)
{
	return get_file_info(szPath, entry, ctx);
}

